#include "InterestRateBondList.h"
#include "../StringResource.h"
#include <core/StyleMgr.h>
#include <widgets/table/STable.h>
#include <widgets/table/STableColumnSet.h>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QTableView>
#include <QHeaderView>
#include <QDateTime>
#include <bondlib/BondContainer.h>
#include <bondlib/BondAuctionInfo.h>
#include <bondlib/AdditionBondInfo.h>
#include <bondlib/SSVContainer.h>
#include <uam/ServerTimeMgr.h>
#include <qbtools/tools.h>

InterestRateBondList::InterestRateBondList(QWidget* p)
	: QWidget(p),
	  m_table(nullptr),
	  m_model(nullptr),
	  m_tableSet(nullptr)
{
	m_table = new SVirtualTable(this);
	m_model = new DefaultTableModel(this);
	m_model->setTable(m_table);

	QVBoxLayout* mainLayout = new QVBoxLayout(this);
	mainLayout->setContentsMargins(0, 0, 0, 0);
	mainLayout->addWidget(m_table);
	setLayout(mainLayout);

	m_table->table()->setModel(m_model);
	m_table->table()->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
	m_table->table()->horizontalHeader()->show();
	initTable();
}

void InterestRateBondList::initTable()
{
#define ALIGN_RIGHT  (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignRight)
#define ALIGN_LEFT  (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignLeft)
#define ALIGN_CENTER  (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignCenter)

	m_tableSet = new STableColumnSet(m_table, "InterestRateBondList", this);
	m_tableSet->setSaveCfg(true);

	BEGIN_COLUMN;
	ADD_COLUMN(fuCol_ISSUEDATE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_ISSUEDATE), 0, 80, 12, 0.12, false, ALIGN_LEFT, kAuto, "");
	m_cols.push_back(fuCol_ISSUEDATE);
	ADD_COLUMN(fuCol_NAME, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_NAME), 0, 80, 12, 0.09, false, ALIGN_LEFT, kAuto, "");
	m_cols.push_back(fuCol_NAME);
	ADD_COLUMN(fuCol_TERM, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_TERM), 0, 50, 40, 0.09, false, ALIGN_CENTER, kAuto, "");
	m_cols.push_back(fuCol_TERM);
	ADD_COLUMN(fuCol_ISSUE_AMOUNT, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_ISSUE_AMOUNT), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_ISSUE_AMOUNT);
	ADD_COLUMN(fuCol_AUCTION_TIME, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_AUCTION_TIME), 0, 85, 12, 0.1, false, ALIGN_LEFT, kAuto, "");
	m_cols.push_back(fuCol_AUCTION_TIME);
	ADD_COLUMN(fuCol_ISSUE_RATE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_ISSUE_RATE), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_ISSUE_RATE);
	ADD_COLUMN(fuCol_MARGINAL_RATE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_MARGINAL_RATE), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_MARGINAL_RATE);
	ADD_COLUMN(fuCol_TOTAL_MULTIPLIER, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_TOTAL_MULTIPLIER), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_TOTAL_MULTIPLIER);
	ADD_COLUMN(fuCol_MARGINAL_MULTIPLIER, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_MARGINAL_MULTIPLIER), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_MARGINAL_MULTIPLIER);
	ADD_COLUMN(fuCol_SETTLEMENT_DATE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_SETTLEMENT_DATE), 1, 85, 12, 0.1, false, ALIGN_LEFT, kAuto, "");
	m_cols.push_back(fuCol_SETTLEMENT_DATE);
	ADD_COLUMN(fuCol_LISTING_DATE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_LISTING_DATE), 1, 85, 12, 0.1, false, ALIGN_LEFT, kAuto, "");
	m_cols.push_back(fuCol_LISTING_DATE);
	ADD_COLUMN(fuCol_HISTORY_ISSUE, m_tableSet, NewStringTable::strFixedIncomeInterestRateBondList(fuCol_HISTORY_ISSUE), 1, 75, 12, 0.09, false, ALIGN_RIGHT, kAuto, "");
	m_cols.push_back(fuCol_HISTORY_ISSUE);
	m_tableSet->apply();
	m_tableSet->setMenuCfg(kDft);

	connect(m_table, &SVirtualTable::viewPosChanged, [=](int)
		{
			updateTable(false);
		});

	m_tableSet->setFrozenCols(2);
}

void InterestRateBondList::setBondIndexs(const std::vector<int>& bondIndexs) {
	m_bondIndexs = bondIndexs;
	Sort();
	updateTable(true);
}

void InterestRateBondList::Sort()
{
	if (m_bondIndexs.size() <= 0){
		return;
	}

	QDateTime currentTime = QDateTime::fromTime_t(CSSVContainer::GetServerTime());
	int today = currentTime.date().year()*10000 + currentTime.date().month()*100 + currentTime.date().day();

	class compare_issuestart_date {
	public:
		compare_issuestart_date(int today) { m_today = today; };
		bool operator() (int nIdx1, int nIdx2)
		{
			const CBondInfo& bi1 = CBondContainer::instance().ElementAtR(nIdx1);
			const CBondInfo& bi2 = CBondContainer::instance().ElementAtR(nIdx2);
			int d1 = atoi(bi1.GetIssueStartDate());
			int d2 = atoi(bi2.GetIssueStartDate());
			int ret = d1 - d2;
			if (ret != 0) return (ret > 0 ? false : true);

			const CBondAuctionInfo* ai1 = CBondContainer::instance().GetBondAuctionInfo(nIdx1);
			const CBondAuctionInfo* ai2 = CBondContainer::instance().GetBondAuctionInfo(nIdx2);
			if (ai1)d1 = ai1->GetAuctionTimeStart();
			else d1 = bi1.GetAuctionTimeStart();
			if (ai2)d2 = ai2->GetAuctionTimeStart();
			else d2 = bi2.GetAuctionTimeStart();
			if (d1 != d2) return d1 < d2;

			if (ai1)d1 = ai1->GetAuctionTimeEnd();
			else d1 = bi1.GetAuctionTimeEnd();
			if (ai2)d2 = ai2->GetAuctionTimeEnd();
			else d2 = bi2.GetAuctionTimeEnd();
			if (d1 != d2) return d1 < d2;

			const char* sShortName1 = bi1.GetBondShortName();
			const char* sShortName2 = bi2.GetBondShortName();
			return strcmp(sShortName1, sShortName2) < 0;
		};
	private:
		int m_today;
	}sortFun(today);

	std::sort(m_bondIndexs.begin(), m_bondIndexs.end(), sortFun);
}

void InterestRateBondList::updateTable(bool reset)
{
	QFont f = font();
	f.setPixelSize(13);
	f.setBold(true);

	UINT today = ServerTimeMgr::instance().today();
	QString strText;
	CBondContainer& bc = CBondContainer::instance();

	m_table->clearTable();

	int realCount = m_bondIndexs.size();
	int pageCount = m_table->pageCount();
	pageCount = std::min(pageCount, realCount);
	int pos = reset ? 0 : m_table->sliderPos();
	m_table->setRealDataCount(realCount);

	int colCount = m_model->columnCount();
	for (int row=0; row<pageCount; ++row)
	{
		if (pos+row<0 || pos+row>=(int)m_bondIndexs.size()) {
			break;
		}

		int bondIndex = m_bondIndexs[pos + row];
		const CBondInfo& bi = bc.ElementAtR(bondIndex);
		const CBondAuctionInfo* ai = bc.GetBondAuctionInfo(bondIndex);

		for (int col = 0; col < colCount; ++col)
		{
			if (!m_tableSet->isColVisible(col))
				continue;

			QStandardItem* item = m_model->item(row, col);
			if (item == nullptr) {
				item = new QStandardItem();
			}
			item->clearData();
			item->setData(StyleMgr::instance().color("Highlight"), Qt::ForegroundRole);
			item->setData((int)(Qt::AlignLeft|Qt::AlignVCenter), Qt::TextAlignmentRole);
			item->setData(StyleMgr::instance().color("BasicPlate"), Qt::BackgroundRole);
			item->setData(f, Qt::FontRole);
			QString idStr = QString("%1").arg(bondIndex);
			item->setData(idStr, DataIdRole);

			switch (col) {
			case fuCol_ISSUEDATE:{//发行日
				int date = atoi(bi.GetIssueStartDate());
				if (date == today) {
					strText = NewStringTable::strFixedIncomeToday();
				}
				else {
					strText = QString::asprintf("%04d-%02d-%02d", date/10000, (date%10000)/100, date%100);
				}
				item->setData(StyleMgr::instance().color("TextNormal"), Qt::ForegroundRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_NAME:{//债券简称			
				strText = QString::fromLocal8Bit(bi.GetBondShortName());
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_TERM:{//期限
				int day = atoi(bi.GetInterestStartDate());
				time_t tNow;
				if (day > 0) {
					struct tm now;
					now.tm_year = day/10000 - 1900 - 1;//倒推1年，确保当前日期小于起息日
					now.tm_mon = (day%10000)/100 - 1;
					now.tm_mday = day%100;
					now.tm_hour = 8;
					now.tm_min = 0;
					now.tm_sec = 0;
					tNow = mktime(&now);
				}
				else {
					tNow = today;
					struct tm* now = localtime(&tNow);
					now->tm_year -= 1;//倒推1年，确保当前日期小于起息日
					tNow = mktime(now);
				}
				strText = bi.GetHistoryRemainPeriod(tNow).c_str();
				strText.replace(".00", "");
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_ISSUE_AMOUNT: { //发行量
				double amount = -1;
				if (ai){
					amount = ai->GetActualAuctionAmount();
					if (amount < 1)	amount = ai->GetPlanedAuctionAmount();
				}
				if (amount < 1) amount = bi.GetActualIssueAmount();
				if (amount < 1) amount = bi.GetPlannedIssueAmount();
				if (amount < 1)	strText = "--";
				else {
					//todo 英文版单位与中文版不一样amount /= 100000;//billion
					strText = QString::asprintf("%.04f", amount/10000);//亿
					strText = SSTools::PriceRemoveZero(strText, 0);
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_AUCTION_TIME: {//招标时间
				strText = "";
				int t0 = 0, t1 = 0;
				QString sT0 = "", sT1 = "";
				if (ai) t0 = ai->GetAuctionTimeStart();
				if (t0 <= 0) t0 = bi.GetAuctionTimeStart();
				if (t0 > 0) sT0 = QString::asprintf("%02d:%02d", t0 / 100, t0 % 100);

				if (ai) t1 = ai->GetAuctionTimeEnd();
				if (t1 <= 0) t1 = bi.GetAuctionTimeEnd();
				if (t1 > 0) sT1 = QString::asprintf("%02d:%02d", t1 / 100, t1 % 100);

				if (sT0.length() > 0 || sT1.length() > 0){
					strText = sT0 + "-" + sT1;
				}
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_ISSUE_RATE: {//加权利率
				if (ai) {
					double rate = ai->GetWATenderRate();
					if (rate < 0.000001) {
						strText = "--";
					}
					else {
						strText = QString::asprintf("%.04f", rate);
						strText = SSTools::PriceRemoveZero(strText, 0);
					}
				}
				else {
					strText = "--";
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_MARGINAL_RATE: {//边际利率
				if (ai) {
					double rate = ai->GetMGTenderRate();
					if (rate < 0.000001) {
						strText = "--";
					}
					else {
						strText = QString::asprintf("%.04f", rate);
						strText = SSTools::PriceRemoveZero(strText, 0);
					}
				}
				else {
					strText = "--";
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_TOTAL_MULTIPLIER: {//全场倍数
				if (ai){
					double rate = ai->GetSubscriptionRatio();
					if (rate < 0.000001) {
						strText = "--";
					}
					else {
						strText = QString::asprintf("%.04f", rate);
						strText = SSTools::PriceRemoveZero(strText, 0);
					}
				}
				else {
					strText = "--";
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_MARGINAL_MULTIPLIER: {//边际倍数
				if (ai){
					double rate = ai->GetMarginalRatio();
					if (rate < 0.000001) {
						strText = "--";
					}
					else {
						strText = QString::asprintf("%.04f", rate);
						strText = SSTools::PriceRemoveZero(strText, 0);
					}
				}
				else {
					strText = "--";
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_SETTLEMENT_DATE: {//缴款日
				int date = atoi(bi.GetPaymentDate());
				if (date < 19700000) {
					strText = "--";
				}
				else {
					strText = QString::asprintf("%04d-%02d-%02d", date/10000, (date%10000)/100, date%100);
				}
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_LISTING_DATE: {//上市日
				int date = atoi(bi.GetListDate());
				if (date < 19700000){
					strText = "--";
				}
				else {
					strText = QString::asprintf("%04d-%02d-%02d", date/10000, (date%10000)/100, date%100);
				}
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			case fuCol_HISTORY_ISSUE: {//历史发行日
				double amount = 0.0f;
				int noAddIssue = 0;
				bool ret = GetLastAddIssue(bi, amount, noAddIssue);
				if (ret && amount > 0) {
					//todo 英文版单位与中文版不一样amount /= 100000;//billion
					strText = QString::asprintf("%.04f", amount/10000);//亿
					strText = SSTools::PriceRemoveZero(strText, 0);
					std::string fmt = NewStringTable::strFixedIncomeGovBondIssuance(8).toStdString();
					QString tips = QString::asprintf(fmt.c_str(), noAddIssue);
					item->setToolTip(tips);
				}
				else {
					strText = "--";
				}
				item->setData((int)(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
				item->setData(strText, Qt::DisplayRole);
				break;
			}
			default:
				break;
			}
			m_model->setItem(row, col, item);
		}
	}
}

bool InterestRateBondList::GetLastAddIssue(const CBondInfo& bi, double& amount, int& noAddIssue) {
	const CAdditionBondInfo* addBondInfo = (const_cast<CBondInfo*>(&bi))->GetAdditionInfo();
	if (addBondInfo == nullptr) {
		return false;
	}

	//获取原券对应所有增发券
	CBondContainer& bc = CBondContainer::instance();
	int firstIssueBondIndex = bc.GetBondIndex(addBondInfo->GetFirstIssueKey());
	std::set<int>* setPtr = nullptr;
	bool ret = bc.GetAdditionList(firstIssueBondIndex, setPtr);
	if (!ret || setPtr == nullptr) {
		return false;
	}

	//当前期数
	int curNoAddIssue = addBondInfo->GetNoAddIssue();

	//获取上一期发行量和期数
	while ((--curNoAddIssue) >= 0) {
		for (std::set<int>::const_iterator iter=setPtr->begin(); iter!=setPtr->end(); ++iter) {
			const CBondInfo& tmpBi = bc.ElementAtR(*iter);
			const CAdditionBondInfo* tmpAddBondInfo = (const_cast<CBondInfo*>(&tmpBi))->GetAdditionInfo();
			if (tmpAddBondInfo != nullptr &&
				tmpAddBondInfo->GetNoAddIssue() == curNoAddIssue) {
				amount = tmpBi.GetActualIssueAmount();
				noAddIssue = curNoAddIssue;
				return true;
			}
		}
	}
	return false;
}
